#include <check.h>
#include <im_base_types.h>
#include <stdio.h>

IMInt imi;
IMInt8 imi8;
IMInt16 imi16;
IMInt32 imi32;
IMInt64 imi64;
IMUInt imui;
IMUInt8 imui8;
IMUInt16 imui16;
IMUInt32 imui32;
IMUInt64 imui64;


START_TEST(base_types_test_sizes)
{
    fail_unless (sizeof (IMInt8) == 1, NULL);
    fail_unless (sizeof (IMUInt8) == 1, NULL);

    fail_unless (sizeof (IMInt16) == 2, NULL);
    fail_unless (sizeof (IMUInt16) == 2, NULL);

    fail_unless (sizeof (IMInt32) == 4, NULL);
    fail_unless (sizeof (IMUInt32) == 4, NULL);

    fail_unless (sizeof (IMInt64) == 8, NULL);
    fail_unless (sizeof (IMUInt64) == 8, NULL);
}
END_TEST


START_TEST(base_types_test_endianness)
{
    IMUInt16 imu16t1 = 0x44afU, imu16t2 = 0xaf44U;
    IMUInt32 imu32t1 = 0x02a7f109U, imu32t2 = 0x09f1a702U;
    IMUInt64 imu64t1 = IM_IMINT64_CONSTANT(0x1d636b02300a7aa7U),
             imu64t2 = IM_IMINT64_CONSTANT(0xa77a0a30026b631dU);

    fail_unless (IMUINT16_SWAP_LE_BE (imu16t1) == imu16t2);
    fail_unless (IMUINT32_SWAP_LE_BE (imu32t1) == imu32t2);
    fail_unless (IMUINT64_SWAP_LE_BE (imu64t1) == imu64t2);
}
END_TEST


START_TEST(base_types_test_minmax_bound)
{
    imui = IM_MAXUINT;
    imui++;
    fail_unless (imui == 0);

    imui16 = IM_MAXUINT16;
    imui16++;
    fail_unless (imui16 == 0);

    imui32 = IM_MAXUINT32;
    imui32++;
    fail_unless (imui32 == 0);

    imui64 = IM_MAXUINT64;
    imui64++;
    fail_unless (imui64 == 0);

    /*
     * FIXME: the following tests fail (the integers do not overflow back to MININT)
     *        when compiled with -O2 for some reason.
     */

    imi = IM_MAXINT;
    imi++;
    fail_unless (imi == IM_MININT, "IM_MAXINT = %d, IM_MININT = %d, imi = %d", IM_MAXINT, IM_MININT, imi);

    imi16 = IM_MAXINT16;
    imi16++;
    fail_unless (imi16 == IM_MININT16, "IM_MAXINT16 = %d, IM_MININT16 = %d, imi16 = %d", IM_MAXINT16, IM_MININT16, imi16);

    imi32 = IM_MAXINT32;
    imi32++;
    fail_unless (imi32 == IM_MININT32, "IM_MAXINT32 = %d, IM_MININT32 = %d, imi32 = %d", IM_MAXINT32, IM_MININT32, imi32);

    imi64 = IM_MAXINT64;
    imi64++;
    fail_unless (imi64 == IM_MININT64);
}
END_TEST


START_TEST(base_types_test_format_macros)
{
#define FORMAT64 "%" IM_IMINT64_FORMAT " %" IM_IMUINT64_FORMAT "\n"
    char string[1024];
    IMInt64 i64t1 = IM_IMINT64_CONSTANT (-0x3AFAFAFAFAFAFAFA), i64t2;
    IMUInt64 u64t1 = IM_IMUINT64_CONSTANT (0xFAFAFAFAFAFAFAFA), u64t2;

    sprintf (string, FORMAT64, i64t1, u64t1);
    sscanf (string, FORMAT64, &i64t2, &u64t2);

    fail_unless (i64t1 == i64t2);
    fail_unless (u64t1 == u64t2);
}
END_TEST


Suite *
base_types_suite (void)
{
    Suite *s;
    TCase *tc;

    s = suite_create ("base-types");

    tc = tcase_create ("sizes");
    suite_add_tcase (s, tc);
    tcase_add_test (tc, base_types_test_sizes);
    tcase_set_timeout (tc, 100);

    tc = tcase_create ("endianness");
    suite_add_tcase (s, tc);
    tcase_add_test (tc, base_types_test_endianness);
    tcase_set_timeout (tc, 100);

    tc = tcase_create ("minmax_bound");
    suite_add_tcase (s, tc);
    tcase_add_test (tc, base_types_test_minmax_bound);
    tcase_set_timeout (tc, 100);

    tc = tcase_create ("format_macros");
    suite_add_tcase (s, tc);
    tcase_add_test (tc, base_types_test_format_macros);
    tcase_set_timeout (tc, 100);

    return s;
}

// vi:ts=4:sw=4:nowrap:cin:expandtab
